﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FCS.Communication;
using System.IO;
using FCS.GlobalComponents;
using System.Threading;

namespace FCS.Pattern
{
    /// <summary>
    /// This class manages the bollards and responds to their input by playing a sequence or music
    /// </summary>
    /// <param preloadPatterns> Dictates if the the default vavle sequences should be loaded. 
    /// </param>
    public class BollardController : Controller
    {
        /// <summary>
        /// Sets up the bollard controller by reading the code and patterns off of the disk.
        /// </summary>
        /// <param name="defaultSequence">True - run the default patterns at a low priority level
        /// false - run at the music priority level</param>
        public BollardController(bool defaultSequence)
            : base()
        {
            EventLogWriter _eventLogWriter = new EventLogWriter("Default Bollard Service");

            StreamReader sr = new StreamReader(@"C:\FountainData\bollardCode.txt");
            _code = sr.ReadLine();
            sr.Close();
            sr.Dispose();
            SetDefaultCRIOAddress();


            // if we are running the default sequences, load the lower priority
            if (defaultSequence)
            {
                _controllerPriority = CommandPriority.bollards;

                // read in the patterns
                try
                {
                    DirectoryInfo di = new DirectoryInfo(@"C:\FountainData\Bollard Patterns");
                    ReadPatterns(di);

                    if (_patterns.Count != FCS.GlobalComponents.FountainConstants.BollardCount)
                        throw new FormatException("There should be " + FCS.GlobalComponents.FountainConstants.BollardCount + " sequence files. " + _patterns.Count + " were loaded instead.");
                }
                catch (Exception e)
                {
                    _eventLogWriter.WriteToLog(System.Diagnostics.EventLogEntryType.Error, "An error occured when reading in the sequences.\n" + e.Message + "\n\nInner Exception:\n" + e.InnerException);
                }
            }
            else
            {
                _controllerPriority = CommandPriority.music;
            }

            // read in the restricted valves
            string folderPath = @"C:\FountainData\RestrictedBollardValves.txt";
            _eventLogWriter.WriteToLog(System.Diagnostics.EventLogEntryType.Information, "Reading restricted valves"); 
            try
            {
                // Read in restirected valves
                StreamReader sr2 = new StreamReader(folderPath);
                List<string> restricted = new List<string>();
                while (!sr2.EndOfStream)
                {
                    restricted.Add(sr2.ReadLine());
                }

                bool sent = false;
                while (!sent)
                {
                    try
                    {
                        // Send restricted valves
                        _connection.AddRestrictedValves(restricted, _controllerPriority, _code);
                        sent = true;
                        _eventLogWriter.WriteToLog(System.Diagnostics.EventLogEntryType.Information, "Sent restricted valves");
                    }
                    catch (Exception e) { _eventLogWriter.WriteToLog(System.Diagnostics.EventLogEntryType.Error, "An error occured when reading in the restricted valves.\n" + e.Message + "\n\nInner Exception:\n" + e.InnerException); }
                }
            }
            catch (IOException)
            {
                EventLogWriter elw = new EventLogWriter("FountainController");
                string message = "Failed to open restriced valve file " + folderPath + " in Fountain Controller! Killing process to prevent damage to valves.";
                elw.WriteToLog(System.Diagnostics.EventLogEntryType.FailureAudit, message);

                throw new ApplicationException(message);
            }
        }

        /// <summary>
        /// The bollards will listen and respond to input from the cRIO and play a pattern. When the pattern is completed, it will check the time
        /// and, if on the hour, will mark off the time
        /// </summary>
        public void Run()
        {
            new Thread(() =>
            {
                while (_patternIsRunning)
                {
                    Listen();
                    MarkTime();
                }
            }).Start();
        }

        /// <summary>
        /// Listen for bollard input and play when reader
        /// </summary>
        void Listen()
        {
            GlobalComponents.cRIOState state = GetState();
            bool[] bollardStates = state.BollardStates;

            for (int i = 0; i < GlobalComponents.FountainConstants.BollardCount; i++)
            {
                if (bollardStates[i] && i < _patterns.Count)
                    PlayPattern(_patterns.ElementAt(i), _controllerPriority);
            }

        }

        /// <summary>
        /// Allows other classes that use this object to also access the state of the cRIO
        /// </summary>
        /// <returns></returns>
        public cRIOState GetState()
        {
            cRIOState s = null;
            lock (_connectionMonitor)
            {
                bool gotsucceeded = false;
                while (!gotsucceeded)
                {
                    try
                    {
                        s = _connection.GetResources();
                        gotsucceeded = true;
                    }
                    catch (Exception) { }
                }
            }
            return s;
        }
    }
}
